const path = require("path");
const queryString = require("querystring");
const url = require('url');
const checkPath = require('../tools/io/i').checkPath;
const redirect = require('../tools/http/response/core/redirect');
const resFile = require('../tools/http/response/core/response_file');
const resError = require('../tools/http/response/core/response_error');
const color = require('chalk');

class Service {
  /**
   * Server
   * @param param
   */
  constructor(param) {
    this.request = param.request;
    this.response = param.response;
    this.publicPath = param.public;
    this.onError = param.onError;
    this.onResponse = param.onResponse;
    this.dynamicPage = param.dynamicPage;
    this.api = param.api;
  }

  static() {
    new Promise((resolve) => {
      this.request.primaryUrl = this.request.url.slice(0);
      this.request.query = queryString.parse(url.parse(this.request.url).query);
      this.request.url = decodeURI(url.parse(this.request.url).pathname);
      this.request.realPath = path.normalize(path.resolve(path.join(__dirname, this.publicPath, this.request.url)));
      resolve();
    }).then(
        //GET case start
        () => {
          new Promise((resolve, reject) => {
            this.request.realPath.indexOf(path.normalize(path.resolve(this.publicPath))) !== -1 ? resolve() : reject();
          }).then(
              //in the root path
              () => {
                new Promise((resolve, reject) => {
                  checkPath(this.request.realPath, (error, isFile) => {
                    !error ? resolve(isFile) : reject(error);
                  })
                }).then(
                    //effective path
                    (isFile) => {
                      new Promise((resolve, reject) => {
                        isFile ? resolve() : reject();
                      }).then(
                          //is a file
                          () => {
                            resFile({
                              response: this.response,
                              statusCode: 200,
                              encoding: this.request.headers['accept-encoding'],
                              realPath: this.request.realPath,
                              cache: true,
                              ifModifiedSince: this.request.headers["if-modified-since"]
                            }, (error, statusCode) => {
                              new Promise((resolve, reject) => {
                                this.onResponse ? resolve(error, statusCode) : reject();
                              }).then(
                                  (error, statusCode) => {
                                    this.onResponse(error, statusCode);
                                  }
                                  , () => {

                                  }
                              ).catch((error) => {
                                new Promise((resolve, reject) => {
                                  this.onError ? resolve(error) : reject(error);
                                }).then(
                                    (error) => {
                                      this.onError(error);
                                    }
                                    , (error) => {
                                      console.log(color.red(error));
                                    }
                                ).catch((error) => {
                                  throw new ReferenceError(error);
                                })
                              })
                            })
                          }
                          //isn't a file
                          , () => {
                            new Promise((resolve, reject) => {
                              this.request.url.slice(-1) === '/' ? resolve() : reject();
                            }).then(
                                //last character is /
                                () => {
                                  new Promise((resolve, reject) => {
                                    checkPath(path.join(this.request.realPath, 'index.html'), (error) => {
                                      !error ? resolve() : reject(error);
                                    })
                                  }).then(
                                      //have index.html
                                      () => {
                                        resFile({
                                          response: this.response,
                                          statusCode: 200,
                                          encoding: this.request.headers['accept-encoding'],
                                          realPath: path.join(this.request.realPath, 'index.html'),
                                          cache: true,
                                          ifModifiedSince: this.request.headers["if-modified-since"]
                                        }, (error, statusCode) => {
                                          new Promise((resolve, reject) => {
                                            this.onResponse ? resolve(error, statusCode) : reject();
                                          }).then(
                                              (error, statusCode) => {
                                                this.onResponse(error, statusCode);
                                              }
                                              , () => {

                                              }
                                          ).catch((error) => {
                                            new Promise((resolve, reject) => {
                                              this.onError ? resolve(error) : reject(error);
                                            }).then(
                                                (error) => {
                                                  this.onError(error);
                                                }
                                                , (error) => {
                                                  console.log(color.red(error));
                                                }
                                            ).catch((error) => {
                                              throw new ReferenceError(error);
                                            })
                                          })
                                        })
                                      }
                                      //have no index.html
                                      , () => {
                                        resError(this.response, 404, (error, statusCode) => {
                                          new Promise((resolve, reject) => {
                                            this.onResponse ? resolve(error, statusCode) : reject();
                                          }).then(
                                              (error, statusCode) => {
                                                this.onResponse(error, statusCode);
                                              }
                                              , () => {

                                              }
                                          ).catch((error) => {
                                            new Promise((resolve, reject) => {
                                              this.onError ? resolve(error) : reject(error);
                                            }).then(
                                                (error) => {
                                                  this.onError(error);
                                                }
                                                , (error) => {
                                                  console.log(color.red(error));
                                                }
                                            ).catch((error) => {
                                              throw new ReferenceError(error);
                                            })
                                          })
                                        })
                                      }
                                  ).catch((error) => {
                                    resError(this.response, 500, (error, statusCode) => {
                                      new Promise((resolve, reject) => {
                                        this.onResponse ? resolve(error, statusCode) : reject();
                                      }).then(
                                          (error, statusCode) => {
                                            this.onResponse(error, statusCode);
                                          }
                                          , () => {

                                          }
                                      ).catch((error) => {
                                        new Promise((resolve, reject) => {
                                          this.onError ? resolve(error) : reject(error);
                                        }).then(
                                            (error) => {
                                              this.onError(error);
                                            }
                                            , (error) => {
                                              console.log(color.red(error));
                                            }
                                        ).catch((error) => {
                                          throw new ReferenceError(error);
                                        })
                                      })
                                    })
                                    new Promise((resolve, reject) => {
                                      this.onError ? resolve(error) : reject(error);
                                    }).then(
                                        (error) => {
                                          this.onError(error);
                                        }
                                        , (error) => {
                                          console.log(color.red(error));
                                        }
                                    ).catch((error) => {
                                      throw new ReferenceError(error);
                                    })
                                  })
                                }
                                //last character isn't /
                                , () => {
                                  redirect(this.response, this.request.url + '/', false, (error, statusCode) => {
                                    new Promise((resolve, reject) => {
                                      this.onResponse ? resolve(error, statusCode) : reject();
                                    }).then(
                                        (error, statusCode) => {
                                          this.onResponse(error, statusCode);
                                        }
                                        , () => {

                                        }
                                    ).catch((error) => {
                                      new Promise((resolve, reject) => {
                                        this.onError ? resolve(error) : reject(error);
                                      }).then(
                                          (error) => {
                                            this.onError(error);
                                          }
                                          , (error) => {
                                            console.log(color.red(error));
                                          }
                                      ).catch((error) => {
                                        throw new ReferenceError(error);
                                      })
                                    })
                                  })
                                }
                            ).catch((error) => {
                              resError(this.response, 500, (error, statusCode) => {
                                new Promise((resolve, reject) => {
                                  this.onResponse ? resolve(error, statusCode) : reject();
                                }).then(
                                    (error, statusCode) => {
                                      this.onResponse(error, statusCode);
                                    }
                                    , () => {

                                    }
                                ).catch((error) => {
                                  new Promise((resolve, reject) => {
                                    this.onError ? resolve(error) : reject(error);
                                  }).then(
                                      (error) => {
                                        this.onError(error);
                                      }
                                      , (error) => {
                                        console.log(color.red(error));
                                      }
                                  ).catch((error) => {
                                    throw new ReferenceError(error);
                                  })
                                })
                              })
                              new Promise((resolve, reject) => {
                                this.onError ? resolve(error) : reject(error);
                              }).then(
                                  (error) => {
                                    this.onError(error);
                                  }
                                  , (error) => {
                                    console.log(color.red(error));
                                  }
                              ).catch((error) => {
                                throw new ReferenceError(error);
                              })
                            })
                          }
                      ).catch((error) => {
                        resError(this.response, 500, (error, statusCode) => {
                          new Promise((resolve, reject) => {
                            this.onResponse ? resolve(error, statusCode) : reject();
                          }).then(
                              (error, statusCode) => {
                                this.onResponse(error, statusCode);
                              }
                              , () => {

                              }
                          ).catch((error) => {
                            new Promise((resolve, reject) => {
                              this.onError ? resolve(error) : reject(error);
                            }).then(
                                (error) => {
                                  this.onError(error);
                                }
                                , (error) => {
                                  console.log(color.red(error));
                                }
                            ).catch((error) => {
                              throw new ReferenceError(error);
                            })
                          })
                        })
                        new Promise((resolve, reject) => {
                          this.onError ? resolve(error) : reject(error);
                        }).then(
                            (error) => {
                              this.onError(error);
                            }
                            , (error) => {
                              console.log(color.red(error));
                            }
                        ).catch((error) => {
                          throw new ReferenceError(error);
                        })
                      })
                    }
                    //invalid path
                    , () => {
                      //dynamicPageCheck
                      new Promise((resolve, reject) => {
                        this.dynamicPage ? resolve() : reject();
                      }).then(
                          () => {
                            this.dynamicPage(this.request, this.response);
                          }
                          , () => {
                            resError(this.response, 404, (error, statusCode) => {
                              new Promise((resolve, reject) => {
                                this.onResponse ? resolve(error, statusCode) : reject();
                              }).then(
                                  (error, statusCode) => {
                                    this.onResponse(error, statusCode);
                                  }
                                  , () => {

                                  }
                              ).catch((error) => {
                                new Promise((resolve, reject) => {
                                  this.onError ? resolve(error) : reject(error);
                                }).then(
                                    (error) => {
                                      this.onError(error);
                                    }
                                    , (error) => {
                                      console.log(color.red(error));
                                    }
                                ).catch((error) => {
                                  throw new ReferenceError(error);
                                })
                              })
                            })
                          }
                      ).catch((error) => {
                        resError(this.response, 500, (error, statusCode) => {
                          new Promise((resolve, reject) => {
                            this.onResponse ? resolve(error, statusCode) : reject();
                          }).then(
                              (error, statusCode) => {
                                this.onResponse(error, statusCode);
                              }
                              , () => {

                              }
                          ).catch((error) => {
                            new Promise((resolve, reject) => {
                              this.onError ? resolve(error) : reject(error);
                            }).then(
                                (error) => {
                                  this.onError(error);
                                }
                                , (error) => {
                                  console.log(color.red(error));
                                }
                            ).catch((error) => {
                              throw new ReferenceError(error);
                            })
                          })
                        })
                        new Promise((resolve, reject) => {
                          this.onError ? resolve(error) : reject(error);
                        }).then(
                            (error) => {
                              this.onError(error);
                            }
                            , (error) => {
                              console.log(color.red(error));
                            }
                        ).catch((error) => {
                          throw new ReferenceError(error);
                        })
                      })
                    }
                ).catch((error) => {
                  resError(this.response, 500, (error, statusCode) => {
                    new Promise((resolve, reject) => {
                      this.onResponse ? resolve(error, statusCode) : reject();
                    }).then(
                        (error, statusCode) => {
                          this.onResponse(error, statusCode);
                        }
                        , () => {

                        }
                    ).catch((error) => {
                      new Promise((resolve, reject) => {
                        this.onError ? resolve(error) : reject(error);
                      }).then(
                          (error) => {
                            this.onError(error);
                          }
                          , (error) => {
                            console.log(color.red(error));
                          }
                      ).catch((error) => {
                        throw new ReferenceError(error);
                      })
                    })
                  })
                  new Promise((resolve, reject) => {
                    this.onError ? resolve(error) : reject(error);
                  }).then(
                      (error) => {
                        this.onError(error);
                      }
                      , (error) => {
                        console.log(color.red(error));
                      }
                  ).catch((error) => {
                    throw new ReferenceError(error);
                  })
                })
              }
              //not in the root path
              , () => {
                resError(this.response, 403, (error, statusCode) => {
                  new Promise((resolve, reject) => {
                    this.onResponse ? resolve(error, statusCode) : reject();
                  }).then(
                      (error, statusCode) => {
                        this.onResponse(error, statusCode);
                      }
                      , () => {

                      }
                  ).catch((error) => {
                    new Promise((resolve, reject) => {
                      this.onError ? resolve(error) : reject(error);
                    }).then(
                        (error) => {
                          this.onError(error);
                        }
                        , (error) => {
                          console.log(color.red(error));
                        }
                    ).catch((error) => {
                      throw new ReferenceError(error);
                    })
                  })
                })
              }
          ).catch((error) => {
            resError(this.response, 500, (error, statusCode) => {
              new Promise((resolve, reject) => {
                this.onResponse ? resolve(error, statusCode) : reject();
              }).then(
                  (error, statusCode) => {
                    this.onResponse(error, statusCode);
                  }
                  , () => {

                  }
              ).catch((error) => {
                new Promise((resolve, reject) => {
                  this.onError ? resolve(error) : reject(error);
                }).then(
                    (error) => {
                      this.onError(error);
                    }
                    , (error) => {
                      console.log(color.red(error));
                    }
                ).catch((error) => {
                  throw new ReferenceError(error);
                })
              })
            })
            new Promise((resolve, reject) => {
              this.onError ? resolve(error) : reject(error);
            }).then(
                (error) => {
                  this.onError(error);
                }
                , (error) => {
                  console.log(color.red(error));
                }
            ).catch((error) => {
              throw new ReferenceError(error);
            })
          })
        }
        //error
        , (error) => {
          resError(this.response, 500, (error, statusCode) => {
            new Promise((resolve, reject) => {
              this.onResponse ? resolve(error, statusCode) : reject();
            }).then(
                (error, statusCode) => {
                  this.onResponse(error, statusCode);
                }
                , () => {

                }
            ).catch((error) => {
              new Promise((resolve, reject) => {
                this.onError ? resolve(error) : reject(error);
              }).then(
                  (error) => {
                    this.onError(error);
                  }
                  , (error) => {
                    console.log(color.red(error));
                  }
              ).catch((error) => {
                throw new ReferenceError(error);
              })
            })
          })
          new Promise((resolve, reject) => {
            this.onError ? resolve(error) : reject(error);
          }).then(
              (error) => {
                this.onError(error);
              }
              , (error) => {
                console.log(color.red(error));
              }
          ).catch((error) => {
            throw new ReferenceError(error);
          })
        }
    ).catch((error) => {
      resError(this.response, 500, (error, statusCode) => {
        new Promise((resolve, reject) => {
          this.onResponse ? resolve(error, statusCode) : reject();
        }).then(
            (error, statusCode) => {
              this.onResponse(error, statusCode);
            }
            , () => {

            }
        ).catch((error) => {
          new Promise((resolve, reject) => {
            this.onError ? resolve(error) : reject(error);
          }).then(
              (error) => {
                this.onError(error);
              }
              , (error) => {
                console.log(color.red(error));
              }
          ).catch((error) => {
            throw new ReferenceError(error);
          })
        })
      })
      new Promise((resolve, reject) => {
        this.onError ? resolve(error) : reject(error);
      }).then(
          (error) => {
            this.onError(error);
          }
          , (error) => {
            console.log(color.red(error));
          }
      ).catch((error) => {
        throw new ReferenceError(error);
      })
    })
  }

  API() {
    new Promise((resolve, reject) => {
      this.api ? resolve() : reject();
    }).then(
        () => {
          this.api.test(this.request, this.response);
        }
        , () => {
          resError(this.response, 400, (error, statusCode) => {
            new Promise((resolve, reject) => {
              this.onResponse ? resolve(error, statusCode) : reject();
            }).then(
                (error, statusCode) => {
                  this.onResponse(error, statusCode);
                }
                , () => {

                }
            ).catch((error) => {
              new Promise((resolve, reject) => {
                this.onError ? resolve(error) : reject(error);
              }).then(
                  (error) => {
                    this.onError(error);
                  }
                  , (error) => {
                    console.log(color.red(error));
                  }
              ).catch((error) => {
                throw new ReferenceError(error);
              })
            })
          })
        }
    ).catch((error) => {
      resError(this.response, 500, (error, statusCode) => {
        new Promise((resolve, reject) => {
          this.onResponse ? resolve(error, statusCode) : reject();
        }).then(
            (error, statusCode) => {
              this.onResponse(error, statusCode);
            }
            , () => {

            }
        ).catch((error) => {
          new Promise((resolve, reject) => {
            this.onError ? resolve(error) : reject(error);
          }).then(
              (error) => {
                this.onError(error);
              }
              , (error) => {
                console.log(color.red(error));
              }
          ).catch((error) => {
            throw new ReferenceError(error);
          })
        })
      })
      new Promise((resolve, reject) => {
        this.onError ? resolve(error) : reject(error);
      }).then(
          (error) => {
            this.onError(error);
          }
          , (error) => {
            console.log(color.red(error));
          }
      ).catch((error) => {
        throw new ReferenceError(error);
      })
    })
  }
}

module.exports = Service;